/**************************************************************************
* This file is part of Hawkengine.
*
* Hawkengine is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hawkengine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Hawkengine.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/


/**************************************************************************
* Dependencies
**************************************************************************/
#include "engine/bounds.h"
#include "engine/util.h"

/**************************************************************************
* Preprocessing
**************************************************************************/

/**************************************************************************
* Types
**************************************************************************/

/**************************************************************************
* Variables
**************************************************************************/
const bounds_type UNIT_BOUNDS = {-0.5, 0.5, -0.5, 0.5};

/**************************************************************************
* Static Variables
**************************************************************************/

/**************************************************************************
* Function Prototypes
**************************************************************************/

/**************************************************************************
* Function Implementations
**************************************************************************/
float bounds_aspect(const bounds_type* bounds)
{
  float height;

  height = bounds_height(bounds);

  if (height == 0) {
    return 0;
  }

  return fabs(bounds_width(bounds) / height);
}

void bounds_center(const bounds_type* bounds, float* x_center, float* y_center)
{
  *x_center = bounds_center_x(bounds);
  *y_center = bounds_center_y(bounds);
}

float bounds_center_x(const bounds_type* bounds)
{
  return (((bounds->right - bounds->left) / 2.0) + bounds->left);
}

float bounds_center_y(const bounds_type* bounds)
{
  return (((bounds->top - bounds->bottom) / 2.0) + bounds->bottom);
}

BOOL bounds_contain(const bounds_type* bounds, float x, float y)
{
  return (_BETWEEN(x, bounds->left, bounds->right) &&
          _BETWEEN(y, bounds->bottom, bounds->top));
}

void bounds_convert_xy(const bounds_type* old_bounds,
                       const bounds_type* new_bounds,
                       float* x, float* y)
{
  *x = change_scale_without_containing(*x, old_bounds->left, old_bounds->right,
        new_bounds->left, new_bounds->right);
  *y = change_scale_without_containing(*y, old_bounds->bottom, old_bounds->top,
        new_bounds->bottom, new_bounds->top);
}

void bounds_convert_xy_scale(const bounds_type* old_bounds,
                             const bounds_type* new_bounds,
                             float* x, float* y)
{
  float old_width, old_height, new_width, new_height;

  old_width = bounds_width(old_bounds);
  old_height = bounds_height(old_bounds);
  new_width = bounds_width(new_bounds);
  new_height = bounds_height(new_bounds);

  *x = change_scale_without_containing(*x, -old_width, old_width,
                                       -new_width, new_width);
  *y = change_scale_without_containing(*y, -old_height, old_height,
                                       -new_height, new_height);
}

BOOL bounds_equal(const bounds_type* bounds1, const bounds_type* bounds2)
{
  return (
    (bounds1->left == bounds2->left) &&
    (bounds1->right == bounds2->right) &&
    (bounds1->bottom == bounds2->bottom) &&
    (bounds1->top == bounds2->top));
}

float bounds_height(const bounds_type* bounds)
{
  return (bounds->top - bounds->bottom);
}

void bounds_keep_aspect(const bounds_type* target_bounds, bounds_type* bounds)
{
  float arBounds, arTarget, height, space, width;

  // fit bounds inside target_bounds, keeping aspect ratio of bounds
  arTarget = bounds_aspect(target_bounds);
  arBounds = bounds_aspect(bounds);

  if (arTarget == 0) {
    return;
  }

  width = bounds_width(bounds);
  height = bounds_height(bounds);

  // keep bounds aspect ratio, and add space to accomodate to target
  if (arTarget > arBounds) {
    space = ((height * arTarget) - width);
    bounds->left -= (space / 2.0);
    bounds->right += (space / 2.0);
  } else {
    space = ((width / arTarget) - height);
    bounds->top += (space / 2.0);
    bounds->bottom -= (space / 2.0);
  }
}

void bounds_shrink(bounds_type* bounds, float percent)
{
  float width, height;

  width = bounds_width(bounds);
  height = bounds_height(bounds);
  bounds->left += (width * percent / 100.0);
  bounds->right -= (width * percent / 100.0);
  bounds->bottom += (height * percent / 100.0);
  bounds->top -= (height * percent / 100.0);
}

void bounds_slide(bounds_type* bounds, float delta_x, float delta_y)
{
  bounds->left += delta_x;
  bounds->right += delta_x;
  bounds->top += delta_y;
  bounds->bottom += delta_y;
}

void bounds_trim_to_aspect(const bounds_type* target_bounds, bounds_type* bounds)
{
  float arBounds, arTarget, height, space, width;

  // trim off excess of bounds to match target_bounds aspect
  arTarget = bounds_aspect(target_bounds);
  arBounds = bounds_aspect(bounds);

  if (arTarget == 0) {
    return;
  }

  width = bounds_width(bounds);
  height = bounds_height(bounds);

  // trim board space to set to new target aspect ratio
  if (arTarget > arBounds) {
    space = (height - (width / arTarget));
    bounds->top -= (space / 2.0);
    bounds->bottom += (space / 2.0);
  } else {
    space = (width - (height * arTarget));
    bounds->left += (space / 2.0);
    bounds->right -= (space / 2.0);
  }
}

float bounds_width(const bounds_type* bounds)
{
  return (bounds->right - bounds->left);
}
